use std::cell::RefCell;
use std::collections::HashMap;
use std::ops::Deref;
use std::rc::Rc;
use regex::{Captures, Regex};
use crate::class_file::cf_constant_info::CFConstantInfoEnum;
use crate::class_file::class_file::ClassFile;
use crate::class::vm_access_flags::{is_public, is_static};
use crate::class::vm_class_attr::{VMClassAttrCode, VMClassAttrEnum};
use crate::class::vm_class_constant_info::VMClassConstantInfoEnum;
use crate::class::vm_class_constant_info::VMClassConstantInfoMethodRef;
use crate::class::vm_class_constant_info::VMClassConstantInfoNameAndType;
use crate::vm_thread::{VMFrame, VMThread};
use crate::vm_val::VMValEnum;

pub struct VMClass {
    pub access_flag: u16,
    pub name: String,
    pub super_class: RefCell<Option<Rc<VMClass>>>,
    pub interfaces: RefCell<Vec<Rc<VMClass>>>,
    pub fields: RefCell<Vec<Rc<RefCell<VMClassField>>>>,
    pub methods: RefCell<Vec<Rc<VMClassMethod>>>,
    pub instance_slot_count: RefCell<i32>,
    pub static_slot: RefCell<HashMap<i32, VMValEnum>>,
    pub constant_pool: RefCell<Vec<Rc<VMClassConstantInfoEnum>>>,
    pub init_status: RefCell<bool>,
}

#[macro_export]
macro_rules! get_constant_info_from_vm_class {
    ($vm_class:expr, $index:expr, $enumname:ident) => ({
        let ro_constant_pool = $vm_class.constant_pool.borrow();
        let constant_info_option = ro_constant_pool.get($index as usize);
        if constant_info_option.is_none() {
            panic!("常量池索引异常")
        }
        let clone_enum = constant_info_option.unwrap();
        match clone_enum.clone().deref() {
            VMClassConstantInfoEnum::$enumname { val } => {
                val.clone()
            }
            _ => { panic!("类型不匹配,从常量池获取常量失败:{},{}", $vm_class.name, $index) }
        }
    })
}


impl VMClass {
    pub fn find_main_method(&self) -> Result<Rc<VMClassMethod>, String> {
        let result = self.find_method(&"main".to_string(), &"([Ljava/lang/String;)V".to_string());
        match result {
            Ok(val) => {
                if is_static(val.access_flags) && is_public(val.access_flags) {
                    Ok(val)
                } else {
                    Err("Method not found".to_string())
                }
            }
            Err(msg) => { Err(msg) }
        }
    }

    pub fn find_method(&self, method_name: &String, method_descriptor: &String) -> Result<Rc<VMClassMethod>, String> {
        let methods = self.methods.borrow();
        for method in methods.iter() {
            if method.name == *method_name && method.descriptor.class_method_descriptor_str == *method_descriptor {
                return Ok(method.clone());
            }
        }
        return Err("Method not found".to_string());
    }


    pub fn find_field(&self, field_name: &String, field_descriptor: &String) -> Result<Rc<RefCell<VMClassField>>, String> {
        let fields = self.fields.borrow();
        for field in fields.iter() {
            let ro_field = field.borrow();
            if ro_field.name == *field_name && ro_field.descriptor == *field_descriptor {
                return Ok(field.clone());
            }
        }
        return Err("Method not found".to_string());
    }


    pub fn has_init(&self) -> bool {
        return *self.init_status.borrow().deref();
    }

    pub fn init(current_vm_class: Rc<VMClass>, frame: Rc<RefCell<VMFrame>>, thread: &VMThread) {
        let mut rw_frame = frame.borrow_mut();
        let new_pc = rw_frame.pc() - 3;
        rw_frame.set_pc(new_pc);
        let clinit_method_result = current_vm_class.find_method(
            &String::from("<clinit>"), &String::from("()V"));
        if clinit_method_result.is_ok() {
            let clinit_method = clinit_method_result.unwrap();
            let get_code_attr_result = clinit_method.get_code_attr();
            if get_code_attr_result.is_err() {
                panic!("{},{},{}", file!(), line!(), get_code_attr_result.err().unwrap());
            }
            let code_attr = get_code_attr_result.unwrap();

            thread.stack.borrow_mut().push(Rc::new(RefCell::new(VMFrame {
                pc: 0,
                code: code_attr.code.clone(),
                method: clinit_method.clone(),
                current_vm_class: current_vm_class.clone(),
                operand_stack: RefCell::new(Vec::with_capacity(code_attr.max_stack as usize)),
                local_vars: RefCell::new(HashMap::with_capacity(code_attr.max_locals as usize)),
            })));
        }
        current_vm_class.init_status.replace(true);
    }
}

/// pub struct FieldInfo {
///     access_flags: u16,
///     name_index: u16,
///     descriptor_index: u16,
///     attributes: RefCell<Vec<AttributeInfoEnum>>,
/// }
pub struct VMClassField {
    pub access_flags: u16,
    pub name: String,
    pub descriptor: String,
    pub slot_id: i32,
}

/// pub struct MethodInfo {
///     access_flags: u16,
///     name_index: u16,
///     descriptor_index: u16,
///     // attributes_count: u16,
///     attributes: RefCell<Vec<AttributeInfoEnum>>,
/// }
pub struct VMClassMethod {
    pub access_flags: u16,
    pub name: String,
    pub descriptor: Box<VMClassMethodDescriptor>,
    pub attributes: RefCell<Vec<VMClassAttrEnum>>,
    pub code_attr_index: usize,
}


impl VMClassMethod {
    pub fn get_code_attr(&self) -> Result<Rc<VMClassAttrCode>, String> {
        let method_attrs = self.attributes.borrow();
        let code_attr_enum = method_attrs.get(self.code_attr_index);
        if code_attr_enum.is_none() {
            return Err("查询Code属性失败".to_string());
        }
        let code_result = match code_attr_enum.unwrap() {
            VMClassAttrEnum::VMClassAttrCode { val } => {
                Ok(val)
            }
            _ => {
                println!("{},{},{}", file!(), line!(), "查询代码属性失败");
                Err("查询代码属性失败".to_string())
            }
        };
        if code_result.is_err() {
            return Err(code_result.err().unwrap());
        }
        return Ok(code_result.unwrap().clone());
    }
}

/// 虚拟机方法描述符
#[derive(Debug)]
pub struct VMClassMethodDescriptor {
    pub class_method_descriptor_str: String,
    pub param_type_list: RefCell<Vec<String>>,
    pub return_type: String,
}

impl VMClassMethodDescriptor {
    fn dup(&self) -> Self {
        let param_type_list = RefCell::new(Vec::new());
        return VMClassMethodDescriptor {
            class_method_descriptor_str: String::from(&self.class_method_descriptor_str),
            param_type_list,
            return_type: String::from(&self.return_type),
        };
    }
}

/// 虚拟机类型描述符
struct VMTypeDescriptor {
    type_desc_str: String,
    vm_type_str: String,
}

impl VMTypeDescriptor {
    pub fn parse(type_desc_str: &String) -> Result<VMTypeDescriptor, String> {
        if type_desc_str.starts_with("[") {
            return Err("UnSupport".to_string());
        }
        if type_desc_str.starts_with("L") {
            let vm_type_str = type_desc_str.replace("L", "");
            return Ok(VMTypeDescriptor {
                type_desc_str: String::from(type_desc_str),
                vm_type_str,
            });
        }

        return Ok(VMTypeDescriptor {
            type_desc_str: String::from(type_desc_str),
            vm_type_str: String::from(type_desc_str),
        });
    }
}